// 1. 数组
// （1）第一种
var arr1 = [1, 2, 3];
console.log(arr1);
let arr2: string[] = ['a', 'b'];
arr2.push('c');
// arr2.push(10)  //报错，因为10不是string类型，是number类型
arr2[0] = '10'   //不报错，因为是string类型

// （2）第二种
let arr3: Array<number> = [1, 2, 3];
let arr4: Array<boolean> = [true, false];

//（3）元组  元组类型允许您定义固定长度和类型的数组。
let arr_5: [number, string, boolean] = [0, '哈哈哈', true];

//联合类型 |   在 TS 中叫联合类型由两个或多个其他类型组成的类型，表示可以是这些类型中的任意一种
let arr_6: (number | string | boolean)[] = [1, 10, '哈哈哈', false];
let arr_7: Array<number | string | boolean> = [10, 'hh'];
let a: number | string = '10';
let b: number | string | boolean[] = [true];

//类型别名允许您为一个类型起一个新的名称，以提高代码的可读性和可维护性
type arrType = (number | boolean)[]
let arr_8: arrType = [false, 10];
console.log(arr_8);



// 2.函数
//函数类型实际上指的是：函数参数和返回值的类型
// 函数声明式
function fn1(n: number, m: string) {
    console.log(n)
    console.log(m)
    console.log(123)
}
fn1(10, 'hhh')

//函数表达式
/*let fn_2 = function (t: boolean | string | number[]) {
    console.log(t)
}
fn_2('false')
fn_2([1, 2])*/

/*let fn_2 = function (t: Array<number>) {
    console.log(t)
}
fn_2([1, 2])*/

//写成箭头函数
let fn_2 = (t: string) => {
    console.log(t)
}
fn_2('false')

// 如果函数没有返回值，那么，它的返回值类型为：void
/*let fn_3 = function (): void {
    console.log(123)
}
fn_3()*/

let fn_3 = function (): number | string | number[] {
    console.log(123)
    // return 10
    // return 10
    return [10]
}
fn_3()

// 写成箭头函数
let fn_4 = (m: string): number => Number(m)
fn_4('hh')


const add = (num1: number, num2: number): number => num1 + num2
console.log('add', add(2, 2));
const add1: (num1: number, num2: number) => number = (num1, num2) => num1 + num2
add1(1, 2)




//3.对象
let obj_1: {
    name: string,
    age: number,
    isLogin: boolean,
    // say(): void
    // say: () => void
    say(n: string): number
    // say: (n: string) => number
} = {
    name: '李四',
    age: 20,
    isLogin: true,
    // say: function (n) {
    // say (n) {
    say: (n) => {
        console.log(123)
        console.log(n)
        return 123
    }
}
obj_1.say('说话')

// 类型别名
type objType = {
    name: string;
    age?: number,
    isLogin: boolean,
    // say(): void
    // say: () => void
    say(n: string): number
    // say: (n: string) => number
}
let obj_2: objType = {
    name: '张三',
    isLogin: false,
    age: 10,
    say: (n) => {
        console.log(n)
        return 234
    }
}


//接口 interface   要用大驼峰命名   当一个对象类型被使用多次，一般会使用接口interface来定义对象的类型。
/*
interface 和 type 的区别
相同点
  都可以给对象指定类型

不同点
  interface 只能为对象指定类型
  type 可以为任意类型指定别名
  type 可以使用映射类型，interface不可以
*/
interface Person {
    name: string,
    age: number,
    isLogin: boolean
}

let obj_3: Person = {
    name: '王五',
    age: 30,
    isLogin: true
}

interface ResType {
    // msg: string,
    // code: number,
    // data: number[],
    // ? 可选
    type?: string,
    pageNum: number,
    pageSize: number,
}
let res = {
    // msg: '操作成功',
    // code: 200,
    // data: [1, 2, 3],
    // type: 'free'
    // type: 'boutique',
    pageNum: 1,
    pageSize: 5,
}
let myList: ResType = res



// 继承
interface A {
    name: string
}
interface B extends A {
    age: number
}

let zs: B = {
    age: 0,
    name: '张三'
}

// 类型断言
let fn_5 = function (params: number[] | string | number) {
    // console.log(params.length)
    // console.log((params as string).length)
    console.log((<string>params).length)
}
 fn_5(123)
 // fn_5([123, 1])

// 枚举
enum CourseType {
    '免费' = -1,
    'boutique',
    'discount' = 6
}

let courseRes = {
    msg: '操作成功',
    code: 200,
    data: {
        type: 0
    }
}
console.log(CourseType[courseRes.data.type])


// any  不推荐使用any这会让TypeScript变为AnyScript（失去TS类型保护）  当值的类是any时，可以对值进行任意操作，并且不会有代码提示。
// let n: any;
// let m;
// console.log(m)